home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / DirectInput / Joystick / joystick.cpp next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  15.1 KB  |  425 lines

  1. //-----------------------------------------------------------------------------
  2. // File: Joystick.cpp
  3. //
  4. // Desc: Demonstrates an application which receives immediate 
  5. //       joystick data in exclusive mode via a dialog timer.
  6. //
  7. // Copyright (c) Microsoft Corporation. All rights reserved.
  8. //-----------------------------------------------------------------------------
  9. #define STRICT
  10. #define DIRECTINPUT_VERSION 0x0800
  11.  
  12. #include <windows.h>
  13. #include <commctrl.h>
  14. #include <basetsd.h>
  15. #include <dinput.h>
  16. #include "resource.h"
  17.  
  18.  
  19.  
  20.  
  21. //-----------------------------------------------------------------------------
  22. // Function-prototypes
  23. //-----------------------------------------------------------------------------
  24. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  25. BOOL CALLBACK    EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext );
  26. BOOL CALLBACK    EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* pContext );
  27. HRESULT InitDirectInput( HWND hDlg );
  28. VOID    FreeDirectInput();
  29. HRESULT UpdateInputState( HWND hDlg );
  30.  
  31.  
  32.  
  33.  
  34. //-----------------------------------------------------------------------------
  35. // Defines, constants, and global variables
  36. //-----------------------------------------------------------------------------
  37. #define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }
  38. #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
  39.  
  40. LPDIRECTINPUT8       g_pDI              = NULL;         
  41. LPDIRECTINPUTDEVICE8 g_pJoystick        = NULL;     
  42.  
  43.  
  44.  
  45.  
  46. //-----------------------------------------------------------------------------
  47. // Name: WinMain()
  48. // Desc: Entry point for the application.  Since we use a simple dialog for 
  49. //       user interaction we don't need to pump messages.
  50. //-----------------------------------------------------------------------------
  51. int APIENTRY WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, int )
  52. {
  53.     InitCommonControls();
  54.  
  55.     // Display the main dialog box.
  56.     DialogBox( hInst, MAKEINTRESOURCE(IDD_JOYST_IMM), NULL, MainDlgProc );
  57.     
  58.     return TRUE;
  59. }
  60.  
  61.  
  62.  
  63.  
  64. //-----------------------------------------------------------------------------
  65. // Name: MainDialogProc
  66. // Desc: Handles dialog messages
  67. //-----------------------------------------------------------------------------
  68. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  69. {
  70.     switch( msg ) 
  71.     {
  72.         case WM_INITDIALOG:
  73.             if( FAILED( InitDirectInput( hDlg ) ) )
  74.             {
  75.                 MessageBox( NULL, TEXT("Error Initializing DirectInput"), 
  76.                             TEXT("DirectInput Sample"), MB_ICONERROR | MB_OK );
  77.                 EndDialog( hDlg, 0 );
  78.             }
  79.  
  80.             // Set a timer to go off 30 times a second. At every timer message
  81.             // the input device will be read
  82.             SetTimer( hDlg, 0, 1000 / 30, NULL );
  83.             return TRUE;
  84.  
  85.         case WM_ACTIVATE:
  86.             if( WA_INACTIVE != wParam && g_pJoystick )
  87.             {
  88.                 // Make sure the device is acquired, if we are gaining focus.
  89.                 g_pJoystick->Acquire();
  90.             }
  91.             return TRUE;
  92.  
  93.         case WM_TIMER:
  94.             // Update the input device every timer message
  95.             if( FAILED( UpdateInputState( hDlg ) ) )
  96.             {
  97.                 KillTimer( hDlg, 0 );    
  98.                 MessageBox( NULL, TEXT("Error Reading Input State. ") \
  99.                             TEXT("The sample will now exit."), TEXT("DirectInput Sample"), 
  100.                             MB_ICONERROR | MB_OK );
  101.                 EndDialog( hDlg, TRUE ); 
  102.             }
  103.             return TRUE;
  104.  
  105.         case WM_COMMAND:
  106.             switch( LOWORD(wParam) )
  107.             {
  108.                 case IDCANCEL:
  109.                     EndDialog( hDlg, 0 );
  110.                     return TRUE;
  111.             }
  112.  
  113.         case WM_DESTROY:
  114.             // Cleanup everything
  115.             KillTimer( hDlg, 0 );    
  116.             FreeDirectInput();    
  117.             return TRUE;    
  118.     }
  119.  
  120.     return FALSE; // Message not handled 
  121. }
  122.  
  123.  
  124.  
  125.  
  126. //-----------------------------------------------------------------------------
  127. // Name: InitDirectInput()
  128. // Desc: Initialize the DirectInput variables.
  129. //-----------------------------------------------------------------------------
  130. HRESULT InitDirectInput( HWND hDlg )
  131. {
  132.     HRESULT hr;
  133.  
  134.     // Register with the DirectInput subsystem and get a pointer
  135.     // to a IDirectInput interface we can use.
  136.     // Create a DInput object
  137.     if( FAILED( hr = DirectInput8Create( GetModuleHandle(NULL), DIRECTINPUT_VERSION, 
  138.                                          IID_IDirectInput8, (VOID**)&g_pDI, NULL ) ) )
  139.         return hr;
  140.  
  141.     // Look for a simple joystick we can use for this sample program.
  142.     if( FAILED( hr = g_pDI->EnumDevices( DI8DEVCLASS_GAMECTRL, 
  143.                                          EnumJoysticksCallback,
  144.                                          NULL, DIEDFL_ATTACHEDONLY ) ) )
  145.         return hr;
  146.  
  147.     // Make sure we got a joystick
  148.     if( NULL == g_pJoystick )
  149.     {
  150.         MessageBox( NULL, TEXT("Joystick not found. The sample will now exit."),  
  151.                     TEXT("DirectInput Sample"), 
  152.                     MB_ICONERROR | MB_OK );
  153.         EndDialog( hDlg, 0 );
  154.         return S_OK;
  155.     }
  156.  
  157.     // Set the data format to "simple joystick" - a predefined data format 
  158.     //
  159.     // A data format specifies which controls on a device we are interested in,
  160.     // and how they should be reported. This tells DInput that we will be
  161.     // passing a DIJOYSTATE2 structure to IDirectInputDevice::GetDeviceState().
  162.     if( FAILED( hr = g_pJoystick->SetDataFormat( &c_dfDIJoystick2 ) ) )
  163.         return hr;
  164.  
  165.     // Set the cooperative level to let DInput know how this device should
  166.     // interact with the system and with other DInput applications.
  167.     if( FAILED( hr = g_pJoystick->SetCooperativeLevel( hDlg, DISCL_EXCLUSIVE | 
  168.                                                              DISCL_FOREGROUND ) ) )
  169.         return hr;
  170.  
  171.     // Enumerate the joystick objects. The callback function enabled user
  172.     // interface elements for objects that are found, and sets the min/max
  173.     // values property for discovered axes.
  174.     if( FAILED( hr = g_pJoystick->EnumObjects( EnumObjectsCallback, 
  175.                                                 (VOID*)hDlg, DIDFT_ALL ) ) )
  176.         return hr;
  177.  
  178.     return S_OK;
  179. }
  180.  
  181.  
  182.  
  183.  
  184. //-----------------------------------------------------------------------------
  185. // Name: EnumJoysticksCallback()
  186. // Desc: Called once for each enumerated joystick. If we find one, create a
  187. //       device interface on it so we can play with it.
  188. //-----------------------------------------------------------------------------
  189. BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance,
  190.                                      VOID* pContext )
  191. {
  192.     HRESULT hr;
  193.  
  194.     // Obtain an interface to the enumerated joystick.
  195.     hr = g_pDI->CreateDevice( pdidInstance->guidInstance, &g_pJoystick, NULL );
  196.  
  197.     // If it failed, then we can't use this joystick. (Maybe the user unplugged
  198.     // it while we were in the middle of enumerating it.)
  199.     if( FAILED(hr) ) 
  200.         return DIENUM_CONTINUE;
  201.  
  202.     // Stop enumeration. Note: we're just taking the first joystick we get. You
  203.     // could store all the enumerated joysticks and let the user pick.
  204.     return DIENUM_STOP;
  205. }
  206.  
  207.  
  208.  
  209.  
  210. //-----------------------------------------------------------------------------
  211. // Name: EnumObjectsCallback()
  212. // Desc: Callback function for enumerating objects (axes, buttons, POVs) on a 
  213. //       joystick. This function enables user interface elements for objects
  214. //       that are found to exist, and scales axes min/max values.
  215. //-----------------------------------------------------------------------------
  216. BOOL CALLBACK EnumObjectsCallback( const DIDEVICEOBJECTINSTANCE* pdidoi,
  217.                                    VOID* pContext )
  218. {
  219.     HWND hDlg = (HWND)pContext;
  220.  
  221.     static int nSliderCount = 0;  // Number of returned slider controls
  222.     static int nPOVCount = 0;     // Number of returned POV controls
  223.  
  224.     // For axes that are returned, set the DIPROP_RANGE property for the
  225.     // enumerated axis in order to scale min/max values.
  226.     if( pdidoi->dwType & DIDFT_AXIS )
  227.     {
  228.         DIPROPRANGE diprg; 
  229.         diprg.diph.dwSize       = sizeof(DIPROPRANGE); 
  230.         diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
  231.         diprg.diph.dwHow        = DIPH_BYID; 
  232.         diprg.diph.dwObj        = pdidoi->dwType; // Specify the enumerated axis
  233.         diprg.lMin              = -1000; 
  234.         diprg.lMax              = +1000; 
  235.     
  236.         // Set the range for the axis
  237.         if( FAILED( g_pJoystick->SetProperty( DIPROP_RANGE, &diprg.diph ) ) ) 
  238.             return DIENUM_STOP;
  239.          
  240.     }
  241.  
  242.  
  243.     // Set the UI to reflect what objects the joystick supports
  244.     if (pdidoi->guidType == GUID_XAxis)
  245.     {
  246.         EnableWindow( GetDlgItem( hDlg, IDC_X_AXIS ), TRUE );
  247.         EnableWindow( GetDlgItem( hDlg, IDC_X_AXIS_TEXT ), TRUE );
  248.     }
  249.     if (pdidoi->guidType == GUID_YAxis)
  250.     {
  251.         EnableWindow( GetDlgItem( hDlg, IDC_Y_AXIS ), TRUE );
  252.         EnableWindow( GetDlgItem( hDlg, IDC_Y_AXIS_TEXT ), TRUE );
  253.     }
  254.     if (pdidoi->guidType == GUID_ZAxis)
  255.     {
  256.         EnableWindow( GetDlgItem( hDlg, IDC_Z_AXIS ), TRUE );
  257.         EnableWindow( GetDlgItem( hDlg, IDC_Z_AXIS_TEXT ), TRUE );
  258.     }
  259.     if (pdidoi->guidType == GUID_RxAxis)
  260.     {
  261.         EnableWindow( GetDlgItem( hDlg, IDC_X_ROT ), TRUE );
  262.         EnableWindow( GetDlgItem( hDlg, IDC_X_ROT_TEXT ), TRUE );
  263.     }
  264.     if (pdidoi->guidType == GUID_RyAxis)
  265.     {
  266.         EnableWindow( GetDlgItem( hDlg, IDC_Y_ROT ), TRUE );
  267.         EnableWindow( GetDlgItem( hDlg, IDC_Y_ROT_TEXT ), TRUE );
  268.     }
  269.     if (pdidoi->guidType == GUID_RzAxis)
  270.     {
  271.         EnableWindow( GetDlgItem( hDlg, IDC_Z_ROT ), TRUE );
  272.         EnableWindow( GetDlgItem( hDlg, IDC_Z_ROT_TEXT ), TRUE );
  273.     }
  274.     if (pdidoi->guidType == GUID_Slider)
  275.     {
  276.         switch( nSliderCount++ )
  277.         {
  278.             case 0 :
  279.                 EnableWindow( GetDlgItem( hDlg, IDC_SLIDER0 ), TRUE );
  280.                 EnableWindow( GetDlgItem( hDlg, IDC_SLIDER0_TEXT ), TRUE );
  281.                 break;
  282.  
  283.             case 1 :
  284.                 EnableWindow( GetDlgItem( hDlg, IDC_SLIDER1 ), TRUE );
  285.                 EnableWindow( GetDlgItem( hDlg, IDC_SLIDER1_TEXT ), TRUE );
  286.                 break;
  287.         }
  288.     }
  289.     if (pdidoi->guidType == GUID_POV)
  290.     {
  291.         switch( nPOVCount++ )
  292.         {
  293.             case 0 :
  294.                 EnableWindow( GetDlgItem( hDlg, IDC_POV0 ), TRUE );
  295.                 EnableWindow( GetDlgItem( hDlg, IDC_POV0_TEXT ), TRUE );
  296.                 break;
  297.  
  298.             case 1 :
  299.                 EnableWindow( GetDlgItem( hDlg, IDC_POV1 ), TRUE );
  300.                 EnableWindow( GetDlgItem( hDlg, IDC_POV1_TEXT ), TRUE );
  301.                 break;
  302.  
  303.             case 2 :
  304.                 EnableWindow( GetDlgItem( hDlg, IDC_POV2 ), TRUE );
  305.                 EnableWindow( GetDlgItem( hDlg, IDC_POV2_TEXT ), TRUE );
  306.                 break;
  307.  
  308.             case 3 :
  309.                 EnableWindow( GetDlgItem( hDlg, IDC_POV3 ), TRUE );
  310.                 EnableWindow( GetDlgItem( hDlg, IDC_POV3_TEXT ), TRUE );
  311.                 break;
  312.         }
  313.     }
  314.  
  315.     return DIENUM_CONTINUE;
  316. }
  317.  
  318.  
  319.  
  320.  
  321. //-----------------------------------------------------------------------------
  322. // Name: UpdateInputState()
  323. // Desc: Get the input device's state and display it.
  324. //-----------------------------------------------------------------------------
  325. HRESULT UpdateInputState( HWND hDlg )
  326. {
  327.     HRESULT     hr;
  328.     TCHAR       strText[512]; // Device state text
  329.     DIJOYSTATE2 js;           // DInput joystick state 
  330.     TCHAR*      str;
  331.  
  332.     if( NULL == g_pJoystick ) 
  333.         return S_OK;
  334.  
  335.     // Poll the device to read the current state
  336.     hr = g_pJoystick->Poll(); 
  337.     if( FAILED(hr) )  
  338.     {
  339.         // DInput is telling us that the input stream has been
  340.         // interrupted. We aren't tracking any state between polls, so
  341.         // we don't have any special reset that needs to be done. We
  342.         // just re-acquire and try again.
  343.         hr = g_pJoystick->Acquire();
  344.         while( hr == DIERR_INPUTLOST ) 
  345.             hr = g_pJoystick->Acquire();
  346.  
  347.         // hr may be DIERR_OTHERAPPHASPRIO or other errors.  This
  348.         // may occur when the app is minimized or in the process of 
  349.         // switching, so just try again later 
  350.         return S_OK; 
  351.     }
  352.  
  353.     // Get the input's device state
  354.     if( FAILED( hr = g_pJoystick->GetDeviceState( sizeof(DIJOYSTATE2), &js ) ) )
  355.         return hr; // The device should have been acquired during the Poll()
  356.  
  357.     // Display joystick state to dialog
  358.  
  359.     // Axes
  360.     wsprintf( strText, TEXT("%ld"), js.lX ); 
  361.     SetWindowText( GetDlgItem( hDlg, IDC_X_AXIS ), strText );
  362.     wsprintf( strText, TEXT("%ld"), js.lY ); 
  363.     SetWindowText( GetDlgItem( hDlg, IDC_Y_AXIS ), strText );
  364.     wsprintf( strText, TEXT("%ld"), js.lZ ); 
  365.     SetWindowText( GetDlgItem( hDlg, IDC_Z_AXIS ), strText );
  366.     wsprintf( strText, TEXT("%ld"), js.lRx ); 
  367.     SetWindowText( GetDlgItem( hDlg, IDC_X_ROT ), strText );
  368.     wsprintf( strText, TEXT("%ld"), js.lRy ); 
  369.     SetWindowText( GetDlgItem( hDlg, IDC_Y_ROT ), strText );
  370.     wsprintf( strText, TEXT("%ld"), js.lRz ); 
  371.     SetWindowText( GetDlgItem( hDlg, IDC_Z_ROT ), strText );
  372.  
  373.     // Slider controls
  374.     wsprintf( strText, TEXT("%ld"), js.rglSlider[0] ); 
  375.     SetWindowText( GetDlgItem( hDlg, IDC_SLIDER0 ), strText );
  376.     wsprintf( strText, TEXT("%ld"), js.rglSlider[1] ); 
  377.     SetWindowText( GetDlgItem( hDlg, IDC_SLIDER1 ), strText );
  378.  
  379.     // Points of view
  380.     wsprintf( strText, TEXT("%ld"), js.rgdwPOV[0] );
  381.     SetWindowText( GetDlgItem( hDlg, IDC_POV0 ), strText );
  382.     wsprintf( strText, TEXT("%ld"), js.rgdwPOV[1] );
  383.     SetWindowText( GetDlgItem( hDlg, IDC_POV1 ), strText );
  384.     wsprintf( strText, TEXT("%ld"), js.rgdwPOV[2] );
  385.     SetWindowText( GetDlgItem( hDlg, IDC_POV2 ), strText );
  386.     wsprintf( strText, TEXT("%ld"), js.rgdwPOV[3] );
  387.     SetWindowText( GetDlgItem( hDlg, IDC_POV3 ), strText );
  388.  
  389.    
  390.     // Fill up text with which buttons are pressed
  391.     str = strText;
  392.     for( int i = 0; i < 128; i++ )
  393.     {
  394.         if ( js.rgbButtons[i] & 0x80 )
  395.             str += wsprintf( str, TEXT("%02d "), i );
  396.     }
  397.     *str = 0;   // Terminate the string 
  398.  
  399.     SetWindowText( GetDlgItem( hDlg, IDC_BUTTONS ), strText );
  400.  
  401.     return S_OK;
  402. }
  403.  
  404.  
  405.  
  406.  
  407. //-----------------------------------------------------------------------------
  408. // Name: FreeDirectInput()
  409. // Desc: Initialize the DirectInput variables.
  410. //-----------------------------------------------------------------------------
  411. VOID FreeDirectInput()
  412. {
  413.     // Unacquire the device one last time just in case 
  414.     // the app tried to exit while the device is still acquired.
  415.     if( g_pJoystick ) 
  416.         g_pJoystick->Unacquire();
  417.     
  418.     // Release any DirectInput objects.
  419.     SAFE_RELEASE( g_pJoystick );
  420.     SAFE_RELEASE( g_pDI );
  421. }
  422.  
  423.  
  424.  
  425.